home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Games / Tetris / Source / Piece.m < prev    next >
Text File  |  1975-04-26  |  18KB  |  743 lines

  1. #import <appkit/Application.h>
  2. #import <appkit/NXImage.h>
  3. #import <appkit/Window.h>
  4. #import <dpsclient/wraps.h>
  5. #import "Piece.h"
  6. #import "TetMatrix.h"
  7.  
  8. // The number of pixels to move a block at once when it is dropped.
  9. //static const float ANM_DELTA = 12.0;
  10. static const float ANM_DELTA = 28.0;
  11.  
  12. extern long random();
  13. extern void srandom(int seed);
  14. extern int getpid();
  15.  
  16. @implementation Piece
  17.  
  18. #define PIECE_NULL    (unsigned char *)0;
  19. #define SHAPE_NULL    (struct shape *)0;
  20. const int NUM_ROTATIONS = 4;
  21. const int NUM_SHAPES=7;
  22.  
  23. #define XMIN_BOUNDS(BOUNDS)    ((BOUNDS & 0xc0) >> 6)
  24. #define YMIN_BOUNDS(BOUNDS)    ((BOUNDS & 0x30) >> 4)
  25. #define XMAX_BOUNDS(BOUNDS)    ((BOUNDS & 0xc) >> 2)
  26. #define YMAX_BOUNDS(BOUNDS)    (BOUNDS & 0x3)
  27.  
  28. - (void) setShapes
  29. {
  30.     /*  ** 1st shape ** */
  31.  
  32.     shapes[0].table[0][0] = 0x0;
  33.     shapes[0].table[0][1] = 0xf;    // ####
  34.     shapes[0].table[0][2] = 0x0;
  35.     shapes[0].table[0][3] = 0x0;     //  x,y  x1,y1
  36.     shapes[0].bounds[0] = 0x2e;        // (0, 2, 3, 2) 3*4 + 2 = 14 = 0xe 
  37.     shapes[0].points[0] = 10;            // This piece is worth 10 points
  38.  
  39.     shapes[0].table[1][0] = 0x4;    //  #
  40.     shapes[0].table[1][1] = 0x4;    //  #
  41.     shapes[0].table[1][2] = 0x4;    //  #
  42.     shapes[0].table[1][3] = 0x4;    //  #
  43.     shapes[0].bounds[1] = 0x47;        // (1, 0, 1, 3)
  44.     shapes[0].points[1] = 16;
  45.  
  46.     shapes[0].table[2][0] = 0x0;
  47.     shapes[0].table[2][1] = 0xf;    // ####
  48.     shapes[0].table[2][2] = 0x0;
  49.     shapes[0].table[2][3] = 0x0;
  50.     shapes[0].bounds[2] = 0x2e;        // (0, 2, 3, 2)
  51.     shapes[0].points[2] = 10;
  52.  
  53.     shapes[0].table[3][0] = 0x4;    //  #
  54.     shapes[0].table[3][1] = 0x4;    //  #
  55.     shapes[0].table[3][2] = 0x4;    //  #
  56.     shapes[0].table[3][3] = 0x4;    //  #
  57.     shapes[0].bounds[3] = 0x47;        // (1, 0, 1, 3)
  58.     shapes[0].points[3] = 16;
  59.  
  60.  
  61.     /* **  2nd shape ** */
  62.  
  63.     shapes[1].table[0][0] = 0xc;    // ##
  64.     shapes[1].table[0][1] = 0xc;    // ##
  65.     shapes[1].table[0][2] = 0x0;
  66.     shapes[1].table[0][3] = 0x0;
  67.     shapes[1].bounds[0] = 0x27;        // (0, 2, 1, 3)
  68.     shapes[1].points[0] = 12;
  69.  
  70.     shapes[1].table[1][0] = 0xc;    // ##
  71.     shapes[1].table[1][1] = 0xc;    // ##
  72.     shapes[1].table[1][2] = 0x0;
  73.     shapes[1].table[1][3] = 0x0;
  74.     shapes[1].bounds[1] = 0x27;        // (0, 2, 1, 3)
  75.     shapes[1].points[1] = 12;
  76.  
  77.     shapes[1].table[2][0] = 0xc;    // ##
  78.     shapes[1].table[2][1] = 0xc;    // ##
  79.     shapes[1].table[2][2] = 0x0;
  80.     shapes[1].table[2][3] = 0x0;
  81.     shapes[1].bounds[2] = 0x27;        // (0, 2, 1, 3)
  82.     shapes[1].points[2] = 12;
  83.  
  84.     shapes[1].table[3][0] = 0xc;    // ##
  85.     shapes[1].table[3][1] = 0xc;    // ##
  86.     shapes[1].table[3][2] = 0x0;
  87.     shapes[1].table[3][3] = 0x0;
  88.     shapes[1].bounds[3] = 0x27;        // (0, 2, 1, 3)
  89.     shapes[1].points[3] = 12;
  90.  
  91.  
  92.     /* ** 3rd shape ** */
  93.  
  94.     shapes[2].table[0][0] = 0x4;    //  #
  95.     shapes[2].table[0][1] = 0xe;    // ###
  96.     shapes[2].table[0][2] = 0x0;
  97.     shapes[2].table[0][3] = 0x0;
  98.     shapes[2].bounds[0] = 0x2b;        // (0, 2, 2, 3)
  99.     shapes[2].points[0] = 10;
  100.  
  101.     shapes[2].table[1][0] = 0x4;    //  #
  102.     shapes[2].table[1][1] = 0x6;    //  ##
  103.     shapes[2].table[1][2] = 0x4;    //  #
  104.     shapes[2].table[1][3] = 0x0;
  105.     shapes[2].bounds[1] = 0x5b;        // (1, 1, 2, 3)
  106.     shapes[2].points[1] = 10;
  107.  
  108.     shapes[2].table[2][0] = 0x0;
  109.     shapes[2].table[2][1] = 0xe;    // ###
  110.     shapes[2].table[2][2] = 0x4;    //  #
  111.     shapes[2].table[2][3] = 0x0;
  112.     shapes[2].bounds[2] = 0x1a;        // (0, 1, 2, 2)
  113.     shapes[2].points[2] = 12;
  114.  
  115.     shapes[2].table[3][0] = 0x4;    //  #
  116.     shapes[2].table[3][1] = 0xc;    // ##
  117.     shapes[2].table[3][2] = 0x4;    //  #
  118.     shapes[2].table[3][3] = 0x0;
  119.     shapes[2].bounds[3] = 0x17;        // (0, 1, 1, 3)
  120.     shapes[2].points[3] = 10;
  121.  
  122.  
  123.     // 4th shape
  124.  
  125.     shapes[3].table[0][0] = 0xc;    // ##
  126.     shapes[3].table[0][1] = 0x6;    //  ##
  127.     shapes[3].table[0][2] = 0x0;
  128.     shapes[3].table[0][3] = 0x0;
  129.     shapes[3].bounds[0] = 0x2b;        // (0, 2, 2, 3)
  130.     shapes[3].points[0] = 12;
  131.  
  132.     shapes[3].table[1][0] = 0x4;    //  #
  133.     shapes[3].table[1][1] = 0xc;    // ##
  134.     shapes[3].table[1][2] = 0x8;    // #
  135.     shapes[3].table[1][3] = 0x0;
  136.     shapes[3].bounds[1] = 0x17;        // (0, 1, 1, 3)
  137.     shapes[3].points[1] = 14;
  138.  
  139.     shapes[3].table[2][0] = 0xc;    // ##
  140.     shapes[3].table[2][1] = 0x6;    //  ##
  141.     shapes[3].table[2][2] = 0x0;
  142.     shapes[3].table[2][3] = 0x0;
  143.     shapes[3].bounds[2] = 0x2b;        // (0, 2, 2, 3)
  144.     shapes[3].points[2] = 12;
  145.  
  146.     shapes[3].table[3][0] = 0x4;    //  #
  147.     shapes[3].table[3][1] = 0xc;    // ##
  148.     shapes[3].table[3][2] = 0x8;    // #
  149.     shapes[3].table[3][3] = 0x0;
  150.     shapes[3].bounds[3] = 0x17;        // (0, 1, 1, 3)
  151.     shapes[3].points[3] = 14;
  152.  
  153.  
  154.     // 5th shape
  155.  
  156.     shapes[4].table[0][0] = 0x6;    //  ##
  157.     shapes[4].table[0][1] = 0xc;    // ##
  158.     shapes[4].table[0][2] = 0x0;
  159.     shapes[4].table[0][3] = 0x0;
  160.     shapes[4].bounds[0] = 0x2b;        // (0, 2, 2, 3)
  161.     shapes[4].points[0] = 12;
  162.     
  163.     shapes[4].table[1][0] = 0x8;    // #
  164.     shapes[4].table[1][1] = 0xc;    // ##
  165.     shapes[4].table[1][2] = 0x4;    //  #
  166.     shapes[4].table[1][3] = 0x0;
  167.     shapes[4].bounds[1] = 0x17;        // (0, 1, 1, 3)
  168.     shapes[4].points[1] = 14;
  169.     
  170.     shapes[4].table[2][0] = 0x6;    //  ##
  171.     shapes[4].table[2][1] = 0xc;    // ##
  172.     shapes[4].table[2][2] = 0x0;
  173.     shapes[4].table[2][3] = 0x0;
  174.     shapes[4].bounds[2] = 0x2b;        // (0, 2, 2, 3)
  175.     shapes[4].points[2] = 12;
  176.     
  177.     shapes[4].table[3][0] = 0x8;    // #
  178.     shapes[4].table[3][1] = 0xc;    // ##
  179.     shapes[4].table[3][2] = 0x4;    //  #
  180.     shapes[4].table[3][3] = 0x0;
  181.     shapes[4].bounds[3] = 0x17;        // (0, 1, 1, 3)
  182.     shapes[4].points[3] = 14;
  183.  
  184.  
  185.     // 6th shape
  186.  
  187.     shapes[5].table[0][0] = 0x2;    //   #
  188.     shapes[5].table[0][1] = 0xe;    // ###
  189.     shapes[5].table[0][2] = 0x0;
  190.     shapes[5].table[0][3] = 0x0;
  191.     shapes[5].bounds[0] = 0x2b;        // (0, 2, 2, 3)
  192.     shapes[5].points[0] = 6;
  193.  
  194.     shapes[5].table[1][0] = 0x8;    // #
  195.     shapes[5].table[1][1] = 0x8;    // #
  196.     shapes[5].table[1][2] = 0xc;    // ##
  197.     shapes[5].table[1][3] = 0x0;
  198.     shapes[5].bounds[1] = 0x17;        // (0, 1, 1, 3)
  199.     shapes[5].points[1] = 7;
  200.  
  201.     shapes[5].table[2][0] = 0xe;    // ###
  202.     shapes[5].table[2][1] = 0x8;    // #
  203.     shapes[5].table[2][2] = 0x0;
  204.     shapes[5].table[2][3] = 0x0;
  205.     shapes[5].bounds[2] = 0x2b;        // (0, 2, 2, 3)
  206.     shapes[5].points[2] = 6;
  207.  
  208.     shapes[5].table[3][0] = 0xc;    // ##
  209.     shapes[5].table[3][1] = 0x4;    //  #
  210.     shapes[5].table[3][2] = 0x4;    //  #
  211.     shapes[5].table[3][3] = 0x0;
  212.     shapes[5].bounds[3] = 0x17;        // (0, 1, 1, 3)
  213.     shapes[5].points[3] = 7;
  214.  
  215.  
  216.     // 7th shape
  217.  
  218.     shapes[6].table[0][0] = 0xe;    // ###
  219.     shapes[6].table[0][1] = 0x2;    //   #
  220.     shapes[6].table[0][2] = 0x0;
  221.     shapes[6].table[0][3] = 0x0;
  222.     shapes[6].bounds[0] = 0x2b;        // (0, 2, 2, 3)
  223.     shapes[6].points[0] = 6;
  224.  
  225.     shapes[6].table[1][0] = 0x4;    //  #
  226.     shapes[6].table[1][1] = 0x4;    //  #
  227.     shapes[6].table[1][2] = 0xc;    // ##
  228.     shapes[6].table[1][3] = 0x0;
  229.     shapes[6].bounds[1] = 0x17;        // (0, 1, 1, 3)
  230.     shapes[6].points[1] = 7;
  231.  
  232.     shapes[6].table[2][0] = 0x8;    // #
  233.     shapes[6].table[2][1] = 0xe;    // ###
  234.     shapes[6].table[2][2] = 0x0;
  235.     shapes[6].table[2][3] = 0x0;
  236.     shapes[6].bounds[2] = 0x2b;        // (0, 2, 2, 3)
  237.     shapes[6].points[2] = 6;
  238.  
  239.     shapes[6].table[3][0] = 0xc;    // ##
  240.     shapes[6].table[3][1] = 0x8;    // #
  241.     shapes[6].table[3][2] = 0x8;    // #
  242.     shapes[6].table[3][3] = 0x0;
  243.     shapes[6].bounds[3] = 0x17;        // (0, 1, 1, 3)
  244.     shapes[6].points[3] = 7;
  245. }
  246.  
  247. BOOL resize(NXSize *aSize)
  248. {
  249.     BOOL resized = NO;
  250.  
  251.     if (aSize->height > 32) {
  252.         aSize->height = 32;
  253.         resized = YES;
  254.     }
  255.  
  256.     if (aSize->width > 32) {
  257.         aSize->width = 32;
  258.         resized = YES;
  259.     }
  260.     return resized;
  261. }
  262.  
  263. - findBlockImages
  264. {
  265.     int i;
  266.     char buffer[20];
  267.     id image;
  268.     char *blockName;
  269.     BOOL isGameColor = [NXApp isGameColor];
  270.  
  271.     if (isGameColor) {
  272.         blockName = "ColorBlock";
  273.     } else {
  274.         blockName = "MonoBlock";
  275.     }
  276.     for (i=0; i<4; i++) {
  277.         sprintf(buffer, "%s%d", blockName, i+1);
  278.         image = [NXImage findImageNamed:buffer];
  279.         if (image == NULL) {
  280.             fprintf(stderr, "Couldn't find block named %s\n", buffer);
  281.             exit(0);
  282.         }
  283.         blockImage[i] = image;
  284.     }
  285.     // Assuming all the blocks are the same size.
  286.  
  287.     [blockImage[0] getSize:&blockSize];
  288.     if (resize(&blockSize)) {
  289.  
  290. #ifdef DEBUG
  291.         printf("resizing Block Image\n");
  292. #endif
  293.         [bitmap setScalable:YES];
  294.         [bitmap setSize:&blockSize];
  295.     } 
  296.  
  297.     return self;
  298. }
  299.  
  300. - init
  301. {
  302.     [super init];
  303.  
  304.     [self setShapes];
  305.  
  306.     curCol = curRow = 0;
  307.     currentPiece = PIECE_NULL;
  308.     currentShape = SHAPE_NULL;
  309.     currentRotation = shapenum = 0;
  310.  
  311.     invalidRect.origin.x = invalidRect.origin.y =
  312.       invalidRect.size.width = invalidRect.size.height = 0.0;
  313.  
  314.     // Initialized the animation Rect
  315.     {
  316.         NXSize tmp;
  317.         [self findBlockImages];
  318.  
  319.         // Limit size of block image
  320.         [blockImage[0] getSize:&tmp];
  321.         resize(&tmp);
  322.  
  323.         tmp.height *= 4;
  324.         tmp.width *= 4;
  325.  
  326.         anmShape = [[NXImage alloc] initSize:&tmp];
  327.         [anmShape lockFocus];
  328.         PSsetalpha(0.0);                  // make this block transparent
  329.         PSrectfill(0., 0., tmp.width, tmp.height);
  330.         PSsetalpha(1.0);
  331.     }
  332.     anmBackground = nil;
  333.     viewVarsInited = NO;
  334.     dropPoints = 0;
  335.     srandom(getpid());    // Initialize random number generator
  336.  
  337. #ifdef DEBUG
  338.     printf("Piece object initialized\n");
  339. #endif
  340.  
  341.     return self;
  342. }
  343.  
  344. /*
  345.  *  Draw the Piece.
  346.  *  The focus must be locked by on calling object's view before invoking this method.
  347.  */
  348. - draw:sender
  349. {
  350.     unsigned char mask;
  351.     int xc, yc;
  352.     int ycmax;
  353.     NXPoint dPt;
  354.  
  355.     ycmax = MAX_SHAPE_SIZE -
  356.       YMIN_BOUNDS(currentShape->bounds[currentRotation]);
  357.     for (yc = MAX_SHAPE_SIZE -
  358.           YMAX_BOUNDS(currentShape->bounds[currentRotation]) - 1;
  359.           yc < ycmax; yc++) {
  360.               mask = 1 << (MAX_SHAPE_SIZE - 1);
  361.               for (xc = 0; xc < MAX_SHAPE_SIZE; xc++) {
  362.                   if (currentPiece[yc] & mask) {
  363.                       // Call the sender's parent object 
  364.                       [sender point:&dPt for:curRow + MAX_SHAPE_SIZE - yc - 1 :curCol + xc];
  365.                       [bitmap composite:NX_SOVER toPoint:&dPt];
  366.                   }
  367.                   mask >>= 1;
  368.               }
  369.           }
  370.     return self;
  371. }
  372.  
  373.  
  374. /*
  375.  *  Determine what the next piece to drop will be.
  376.  *
  377.  */
  378. - newPiece
  379. {
  380.     int bitmapNum;
  381.  
  382. #ifdef DEBUG
  383.     printf("Generating a new piece\n");
  384. #endif
  385.  
  386.     shapenum = random() % NUM_SHAPES;
  387. //    shapenum = 0;
  388.     currentShape = &shapes[shapenum];
  389.     currentRotation = random() % NUM_ROTATIONS;
  390.     currentPiece = currentShape->table[currentRotation];
  391.  
  392.     bitmapNum = random() % NUM_BITMAPS;
  393.  
  394.     bitmap = blockImage[bitmapNum];
  395.  
  396.     if (bitmap == NULL) {
  397.         printf("Block %d not found\n", bitmapNum);
  398.     }
  399.     return self;
  400. }
  401.  
  402. /*
  403.  *  Needed so other objects can query to set the Window and View sizes.
  404.  */
  405. - getBlockSize:(NXSize *) size
  406. {
  407.     *size = blockSize;
  408.     return self;
  409. }
  410.  
  411. /*
  412.  *  So other objects can query Piece.m about images
  413.  */
  414. - getBlockImage:(int) blockNum
  415. {
  416.     return blockImage[blockNum];
  417. }
  418.  
  419. - (struct pieceInfo *)pieceInfo
  420. {
  421.     static struct pieceInfo info;
  422.  
  423.     info.bitmap = bitmap;
  424.     info.shape = shapenum;
  425.     info.rotation = currentRotation;
  426.     return &info;
  427. }
  428.  
  429.  
  430. - setPiece:(struct pieceInfo *)info
  431. {
  432.     bitmap = info->bitmap;
  433.     [bitmap getSize:&blockSize];
  434.     resize(&blockSize);
  435.     shapenum = info->shape;
  436.     currentShape = &shapes[shapenum];
  437.     currentRotation = info->rotation;
  438.     currentPiece = currentShape->table[currentRotation];
  439.     return self;
  440. }
  441.  
  442. /*
  443.  *  Get the next piece.
  444.  *
  445.  */
  446. - (BOOL)reset:sender piece:(struct pieceInfo *)info
  447. {
  448.     BOOL legalMove;
  449.     unsigned char shapeBounds;
  450.     int xmin, xmax;
  451.     int ymin;
  452.     NXRect bounds;
  453.  
  454. #ifdef DEBUG
  455.     printf("reseting piece\n");
  456. #endif
  457.  
  458.     // info will contain the piece from NextMatrix if Show Next is selected
  459.     // Otherwise, we'll generate a new piece. 
  460.  
  461.     if (info) {
  462.         [self setPiece:info];
  463.     } else {
  464.         [self newPiece];
  465.     }
  466.     shapeBounds = currentShape->bounds[currentRotation];
  467.     xmin = XMIN_BOUNDS(shapeBounds);
  468.     xmax = XMAX_BOUNDS(shapeBounds);
  469.     ymin = YMIN_BOUNDS(shapeBounds);
  470.     curCol = (TETRIS_COLUMNS - (xmax - xmin + 1)) / 2;
  471.     curRow = TETRIS_ROWS - ymin - 1;
  472.  
  473.     if (!viewVarsInited) {
  474.         [sender getBounds:&bounds];
  475.         [sender getIntercell:&intercell];
  476.  
  477.         // Create a new animation background
  478.         anmBackground = [[NXImage alloc] initSize:&bounds.size];
  479.         viewVarsInited = YES;
  480.     }
  481.     if ((legalMove = [self legalMove:sender :curRow :curCol rotation:currentRotation])) {
  482.         [self getInvalidRect:&invalidRect for:sender];
  483.         [sender display:&invalidRect :1];
  484.     }
  485.     dropPoints = 0;
  486.     return legalMove;
  487. }
  488.  
  489.  
  490. - (BOOL)legalMove:sender :(int)row :(int)column rotation:(int)rotation
  491. {
  492.     unsigned char mask;
  493.     int xc, yc;
  494.     int ycmax;
  495.     int ex, ey;
  496.     unsigned char *piece;
  497.  
  498.     piece = currentShape->table[rotation];
  499.     ycmax = MAX_SHAPE_SIZE - YMIN_BOUNDS(currentShape->bounds[rotation]);
  500.     for (yc = MAX_SHAPE_SIZE -
  501.           YMAX_BOUNDS(currentShape->bounds[rotation]) - 1; yc < ycmax; yc++) {
  502.               mask = 1 << (MAX_SHAPE_SIZE - 1);
  503.               for (xc = 0; xc < MAX_SHAPE_SIZE; xc++) {
  504.                   if (piece[yc] & mask) {
  505.                       ey = row + MAX_SHAPE_SIZE - yc - 1;
  506.                       ex = column + xc;
  507.                       if (ex < 0 || ex >= TETRIS_COLUMNS || ey < 0
  508.                             || [sender bitmapAt:ey :ex])
  509.                          return NO;
  510.                   }
  511.                   mask >>= 1;
  512.               }
  513.           }
  514.     return YES;
  515. }
  516.  
  517.  
  518. - left:sender
  519. {
  520.     if ([self legalMove:sender :curRow :(curCol - 1) rotation:currentRotation]) {
  521.         curCol--;
  522.         [sender display:&invalidRect :1];
  523.         [self getInvalidRect:&invalidRect for:sender];
  524.     }
  525.     return self;
  526. }
  527.  
  528. - right:sender
  529. {
  530.     if ([self legalMove:sender :curRow :(curCol + 1) rotation:currentRotation]) {
  531.         curCol++;
  532.         [sender display:&invalidRect :1];
  533.         [self getInvalidRect:&invalidRect for:sender];
  534.     }
  535.     return self;
  536. }
  537.  
  538. - getInvalidRect:(NXRect *)aRect for:sender
  539. {
  540.      unsigned char bounds;
  541.      NXRect unionRect;
  542.  
  543.      bounds = currentShape->bounds[currentRotation];
  544.      [sender getRect:&unionRect for:curRow + YMIN_BOUNDS(bounds) :curCol + XMIN_BOUNDS(bounds)];
  545.      [sender getRect: aRect for:curRow + YMAX_BOUNDS(bounds) :curCol + XMAX_BOUNDS(bounds)];
  546.      NXUnionRect(&unionRect, aRect);
  547.       
  548.      return self;
  549. }
  550.  
  551. - point:(NXPoint *)thePoint for:(int)row :(int)column 
  552. {
  553.     unsigned char bounds = currentShape->bounds[currentRotation];
  554.     int realx = column - curCol - XMIN_BOUNDS(bounds);
  555.     int realy = row - curRow - YMIN_BOUNDS(bounds);
  556.     
  557.     thePoint->x = realx * (intercell.width + blockSize.width);
  558.     thePoint->y = realy * (intercell.height + blockSize.height);
  559.     return self;
  560. }
  561.  
  562. /*
  563.  *  Called when the player his the spacebar to drop the piece. 
  564.  */
  565. - compositeShape:sender
  566. {
  567.     if (anmShape) {          // already exists
  568.         //        [self->anmShape resize:self->invalidRect.size.width :self->invalidRect.size.height];
  569.         //self->anmShape = [NXImage newSize:&self->invalidRect.size];
  570.     } else {                              // create new image
  571.         //self->anmShape = [NXImage newSize:&self->invalidRect.size];
  572.         //.width
  573.         //         :self->invalidRect.size.height type:NX_UNIQUEALPHABITMAP];
  574.         //        [self->anmShape setFlip:NO];
  575.     }
  576.     [anmShape lockFocus];
  577.     PSsetalpha(0.0);                  // Fill the window with alpha
  578.     PSrectfill(0.0, 0.0, self->invalidRect.size.width, self->invalidRect.size.height);
  579.     PSsetalpha(1.0);                  // Draw image w/o alpha
  580.     [self draw:self];
  581.     [anmShape unlockFocus];
  582.  
  583.     return self;
  584. }
  585.  
  586.  
  587. - compositeBackground: sender
  588. {
  589.     NXRect unionRect;
  590.  
  591.     [self getInvalidRect:&unionRect for:sender];
  592.     NXUnionRect(&self->invalidRect, &unionRect);
  593.     [anmBackground lockFocus];
  594.     [sender setPieceVisible:NO];
  595.     [sender drawSelf:&unionRect :1];
  596.     [sender setPieceVisible:YES];
  597.     [anmBackground unlockFocus];
  598.     return self;
  599. }
  600.  
  601. /*
  602.  *  Move the piece rapidly down the screen after the user hits the spacebar.
  603.  *
  604.  */
  605. - animateDrop:sender
  606. {
  607.     NXRect updRect;
  608.     
  609.     [self getInvalidRect:&updRect for:sender];
  610.  
  611.     [sender lockFocus];
  612.  
  613.     // Erase piece by compositing the background over it.
  614.     [anmBackground composite:NX_SOVER fromRect: &invalidRect
  615.        toPoint:&invalidRect.origin];
  616.     
  617.     while (invalidRect.origin.y - ANM_DELTA > updRect.origin.y) {
  618.         invalidRect.origin.y -= ANM_DELTA;
  619.  
  620.         // Show the piece dropping one increment
  621.         [anmShape composite:NX_SOVER toPoint:&invalidRect.origin];
  622.         [[sender window] flushWindow];
  623.  
  624.         // Erase the piece by showing the background
  625.         [anmBackground composite:NX_SOVER fromRect:&invalidRect
  626.             toPoint:&invalidRect.origin];
  627.     }
  628.     [sender unlockFocus];
  629.     
  630.     [anmShape lockFocus];
  631.     [anmShape getSize:&updRect.size];
  632.     PScompositerect(0.0, 0.0, updRect.size.width, updRect.size.height, NX_CLEAR);
  633.     [anmShape unlockFocus];
  634.     return self;
  635. }
  636.  
  637. /*
  638.  * Return the amount of points that we get for this piece.
  639.  */
  640. - (int)points
  641. {
  642.     return currentShape->points[currentRotation] + dropPoints;
  643. }
  644.  
  645. /*
  646.  * Called when the user hits the space bar.
  647.  *
  648.  */
  649. - drop:sender
  650. {
  651.     int ymin;
  652.     int yc;
  653.  
  654.     ymin = YMIN_BOUNDS(currentShape->bounds[currentRotation]);
  655.  
  656.     for (yc = curRow - 1; yc >= -1 - ymin; yc--) {
  657.         if (![self legalMove:sender :yc :curCol rotation:currentRotation])
  658.           break;
  659.     }
  660.     dropPoints += curRow - yc + 1;      // You get extra points for dropping it
  661.     curRow = yc + 1;
  662.  
  663.     [self compositeShape: sender];
  664.     [self compositeBackground: sender];
  665.     [self animateDrop: sender];
  666.  
  667.     [sender display:&invalidRect : 1];
  668.     [self getInvalidRect:&invalidRect for:sender];
  669.     return self;
  670. }
  671.  
  672. /*
  673.  * Move the piece down.
  674.  */
  675. - (BOOL)down:sender
  676. {
  677.     BOOL canGoDown;
  678.  
  679.     if ((canGoDown = [self legalMove:sender :curRow-1 :curCol rotation:currentRotation])){
  680.         curRow--;
  681.         [sender display:&invalidRect :1];
  682.         [self getInvalidRect:&invalidRect for:sender];
  683.     }
  684.     return canGoDown;
  685. }
  686.  
  687. - turn:sender
  688. {    
  689.     int newRotation = (currentRotation + 3) % NUM_ROTATIONS;
  690.     
  691.     if ([self legalMove:sender :curRow :curCol rotation:newRotation]) {
  692.         currentRotation = newRotation;
  693.         currentPiece = currentShape->table[newRotation];
  694.         [sender display:&invalidRect :1];
  695.         [self getInvalidRect:&invalidRect for:sender];
  696.     }
  697.     return self;
  698. }
  699.  
  700. /*
  701.  * Called when the piece has reached the bottom and can no longer be moved.
  702.  *
  703.  * For each block that composes the image, put the block's image id in the
  704.  * proper iconMatrix[row][column] position.  Thus to redraw the screen,
  705.  * we need only to composite the images from the iconMatrix.
  706.  */
  707. - stick:sender
  708. {
  709.     unsigned char mask;
  710.     int col, theRow;
  711.     int rowMax;
  712.  
  713.     rowMax = MAX_SHAPE_SIZE - YMIN_BOUNDS(currentShape->bounds[currentRotation]);
  714.     for (theRow = MAX_SHAPE_SIZE -
  715.           YMAX_BOUNDS(currentShape->bounds[currentRotation]) - 1;
  716.           theRow < rowMax; theRow++) {
  717.               mask = 1 << (MAX_SHAPE_SIZE - 1);
  718.               for (col = 0; col < MAX_SHAPE_SIZE; col++) {
  719.                   // If there's a block in  
  720.                   if (currentPiece[theRow] & mask)
  721.                      // Set the (row, column) of the matrix equal to Block's image.
  722.                      [sender setBitmap:bitmap at:curRow + MAX_SHAPE_SIZE - theRow - 1
  723.                                                 :curCol + col];
  724.                   mask >>= 1;
  725.               }
  726.           }
  727.     return self;
  728. }
  729.  
  730. - (int)getCurRow
  731. {
  732.     return curRow;
  733. }
  734.  
  735. - free
  736. {
  737.     if (anmShape) [anmShape free];
  738.     if (anmBackground) [anmBackground free];
  739.     return [super free];
  740. }
  741.  
  742. @end
  743.